package com.huilian.iotbox.admin.wap.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.huilian.iotbox.admin.wap.service.UserRoleService;
import com.huilian.iotbox.admin.wap.service.UserService;
import com.huilian.iotbox.admin.wap.service.WeiXinService;
import com.huilian.iotbox.data.common.RedisKey;
import com.huilian.iotbox.data.common.ServerResponse;
import com.huilian.iotbox.data.dto.UserDto;
import com.huilian.iotbox.data.dto.WeiXinDto;
import com.huilian.iotbox.data.enums.ApiParamEnum;
import com.huilian.iotbox.data.enums.UserStatusEnum;
import com.huilian.iotbox.data.po.AppletOrOfficialAccount;
import com.huilian.iotbox.data.po.User;
import com.huilian.iotbox.data.po.UserRole;
import com.huilian.iotbox.data.properties.ConfigProperties;
import com.huilian.iotbox.data.properties.ImageProperties;
import com.huilian.iotbox.data.service.AppletOrOfficialAccountCommonService;
import com.huilian.iotbox.data.utils.SnowflakeIdWorker;
import com.huilian.iotbox.data.vo.UserVo;
import com.huilian.tool.applet.wechat.service.WeChatAppletService;
import com.huilian.tool.common.config.AppletWeChatConfig;
import com.huilian.tool.common.config.WeixinConfig;
import com.huilian.tool.common.utils.HttpServiceUtil;
import com.huilian.tool.weixin.service.WeixinService;
import com.huilian.tool.weixin.service.impl.DefaultWeiXnMsgEventServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.map.HashedMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author chenqiwen
 * @CreateDate: 2022-05-13-13-50
 * @Description:
 */
@Slf4j
@Service
public class WeiXinServiceImpl extends DefaultWeiXnMsgEventServiceImpl implements WeiXinService {

    @Autowired
    private UserService userService;
    @Autowired
    private WeixinConfig weixinConfig;
    @Autowired
    private WeixinService weixinService;
    @Autowired
    private UserRoleService userRoleService;
    @Autowired
    private ImageProperties imageProperties;
    @Autowired
    public ConfigProperties configProperties;
    @Autowired
    private AppletWeChatConfig appletWeChatConfig;
    @Autowired
    private WeChatAppletService weChatAppletService;
    @Autowired
    private RedisTemplate<String, Serializable> redisCacheTemplate;
    @Autowired
    private AppletOrOfficialAccountCommonService appletOrOfficialAccountCommonService;

    private String HUI_USERINFO_URL = "https://open.huilianpay.com/output/userInfo?redirectUrl=%s&attach=%s";
    /**
     * 微信授权码网址
     */
    private final String URL_GET_WEIXIN_AUTH_CODE = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect&connect_redirect=1";

    /**
     * 微信通过code换取网页授权access_token
     */
    private final String URL_GET_WEIXIN_OPENID = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";

    private String URL_GET_WEIXIN_USER_INFO = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN";


    @Override
    public String outPutUserInfo(HttpServletRequest request) throws UnsupportedEncodingException {
        StringBuffer url = new StringBuffer();
        //微信返回的授权码
        String code = request.getParameter("code");

        //请求用户的回调地址
        String redirectUrl = request.getParameter("state");

        String appletOrOfficialAccountIdStr = request.getParameter("appletOrOfficialAccountId");


        String appId = weixinConfig.getAppId();
        String appSecret = weixinConfig.getAppSecret();
        //厂家专属公众号
        Integer appletOrOfficialAccountId = null;
        if (!StringUtils.isEmpty(appletOrOfficialAccountIdStr)) {
            appletOrOfficialAccountId = Integer.valueOf(appletOrOfficialAccountIdStr);
            AppletOrOfficialAccount appletOrOfficialAccount = appletOrOfficialAccountCommonService.findOneById(appletOrOfficialAccountId);
            if (!StringUtils.isEmpty(appletOrOfficialAccountId)) {
                appId = appletOrOfficialAccount.getOfficialAccountAppId();
                appSecret = appletOrOfficialAccount.getOfficialAccountAppSecret();
                log.info("outPutUserInfo命中专属公众号");
            }
        }

        String reqUrl = String.format(URL_GET_WEIXIN_OPENID, appId, appSecret, code);

        log.info("reqUrl:" + reqUrl);
        String result = HttpServiceUtil.httpGet(reqUrl);
        log.info("result:" + result);

        String userAgent = request.getHeader("User-Agent").toLowerCase();
        String userInfo = "";
        if (userAgent.contains("micromessenger")) {
            int index = result.indexOf("openid");
            if (index != -1) {
                JSONObject jsonObject = JSONObject.parseObject(result);
                String openId = jsonObject.getString("openid");
                String accessToken = jsonObject.getString("access_token");
                String refreshToken = jsonObject.getString("refresh_token");
                String userInfoUrl = String.format(URL_GET_WEIXIN_USER_INFO, accessToken, openId);
                userInfo = HttpServiceUtil.httpGet(userInfoUrl);

                /**
                 * {"openid":"oIc_V57vlRdv6pc5QnqkSq61DFuM","nickname":"᭄赵᭄ᩚ刚💗এ华ꦿ13782616925","sex":0,"language":"","city":"","province":"","country":"","headimgurl":"https:\/\/thirdwx.qlogo.cn\/mmopen\/vi_32\/YT2QHmMsibFiabjK2ibva5QbtibWxQIEUqLl42ZL7DHI2QC0iasTuY3y9fNQDL1bQL4av8HCkVEx35CFq4dqO4DBqqQ\/132","privilege":[],"unionid":"oCJdU1fFyc8h7xiYW88NjAKBqwrk"}:
                 *
                 * {"errcode":48001,"errmsg":"api unauthorized, rid: 665463a7-4e6989e0-0d051cd2"}:
                 */
                JSONObject userInfoJsonObject = JSONObject.parseObject(userInfo);
                String openIdByUserInfo = userInfoJsonObject.getString("openid");
                if (StringUtils.isEmpty(openIdByUserInfo)) {
                    JSONObject ui = new JSONObject();
                    ui.put("openid", openId);
                    userInfo = JSON.toJSONString(ui);
                    log.info("默认UserInfo: {}: ", userInfo);
                } else {
                    log.info("获取UserInfo成功: {}: ", userInfo);
                }
            } else {
                log.error("获取用户信息失败！{}", result);
                throw new RuntimeException(result);
            }
        }
        url.append(redirectUrl).append("&userInfo=").append(URLEncoder.encode(userInfo, "UTF-8"));

        return "redirect:" + url;
    }

    @Override
    public String login(HttpServletRequest request) throws UnsupportedEncodingException {

        StringBuilder frontEndUrl = new StringBuilder(configProperties.getWapFrontEndUrl());

        String memberInfoJSON = request.getParameter("userInfo");
        log.info("-----------userInfo------------ " + memberInfoJSON);
        if (StringUtils.isEmpty(memberInfoJSON)) {
            frontEndUrl.append("/#/pages/error/error?message=" + URLEncoder.encode("获取会员信息失败，请重新扫码", "utf-8"));
            return "redirect:" + frontEndUrl;
        }
        String attach = request.getParameter("attach");
        log.info("-----------attach------------ " + attach);
        String[] attachArray = attach.split("_");
        log.info("-----------attachArray------------ " + Arrays.toString(attachArray));
        Integer paramCode = Integer.parseInt(attachArray[1]);
        if (attachArray.length < 2) {
            frontEndUrl.append("/#/pages/error/error?message=" + URLEncoder.encode("参数有误", "utf-8"));
            return "redirect:" + frontEndUrl;
        }

        String deviceNo = attachArray[0];
        log.info("-----------deviceNo------------ " + deviceNo);

        JSONObject jsonObject = JSON.parseObject(memberInfoJSON);
        String unionId = jsonObject.getString("unionid");
        String openId = jsonObject.getString("openid");
        String nickName = jsonObject.getString("nickname");

        final String k = SnowflakeIdWorker.nextId();
        if (ApiParamEnum.WAP_REGISTER.getCode().compareTo(paramCode) == 0) {
            // 运营商注册
            User user = new User();
            user.setUnionId(unionId);
            user.setOpenId(openId);
            user.setNickname(nickName);
            redisCacheTemplate.opsForValue().set(String.format(RedisKey.WAP_USER_TEMPORARY_WX_INFO, k), user, 1, TimeUnit.DAYS);

            // 去页面注册
            frontEndUrl.append("/#/pages/register/register?agencyId=1&key=" + k);

            return "redirect:" + frontEndUrl;
        } else if (ApiParamEnum.GET_WECHAT_INFO_SEND_MESSAGE.getCode().compareTo(paramCode) == 0) {
            final Integer userId = Integer.valueOf(request.getParameter("userId"));
            final String appletOrOfficialAccountIdStr = request.getParameter("appletOrOfficialAccountId");
            Integer officialAccountId = null;
            if (!StringUtils.isEmpty(appletOrOfficialAccountIdStr)) {
                officialAccountId = Integer.valueOf(appletOrOfficialAccountIdStr);
            }
            final Integer results = userService.updateOfficialAccountOpenId(userId, openId, officialAccountId);
            frontEndUrl.append("/static/skip.html");

            log.info("results:{}", results);
            log.info("openId:{}", openId);
            log.info("unionId:{}", unionId);
            log.info("appletOrOfficialAccountId:{}", officialAccountId);
            log.info("frontEndUrl:");
            log.info(frontEndUrl.toString());
            return "redirect:" + frontEndUrl;
        }

        User user = userService.getUserByUnionId(unionId, UserStatusEnum.WRITE_OFF.getCode());
        if (StringUtils.isEmpty(user)) {
            frontEndUrl.append("/#/pages/error/error?message=" + URLEncoder.encode("当前微信号尚未注册运营账号，请扫右下角二维码注册", "utf-8"));
            return "redirect:" + frontEndUrl;
        }

        // 从这里开始拼接重定向到前端的url，必选：带上到哪个页面路径和用户信息，可选：机器id
        if (!StringUtils.isEmpty(nickName) && nickName.equals(user.getNickname())) {
            User updateUser = new User();
            updateUser.setId(user.getId());
            updateUser.setNickname(nickName);
            userService.updateUser(updateUser);
        }

        ServerResponse serverResponse = userService.officialAccountSimulatedAccountLogin(user);
        if (!serverResponse.getIsSuccess()) {
            frontEndUrl.append("/#/pages/error/error?message=" + URLEncoder.encode(serverResponse.getMsg(), "utf-8"));
            return "redirect:" + frontEndUrl;
        }

        String token = user.getToken();

        frontEndUrl.append("/#/pages/smart-marketing-coin-changer/smart-marketing-coin-changer?");
        frontEndUrl.append("&token=" + token);
        frontEndUrl.append("&deviceNo=" + deviceNo);
        return "redirect:" + frontEndUrl;
    }


    /**
     * 微信小程序登录
     *
     * @param weiXinDto
     * @param request
     * @return 10001:未绑定账号
     */
    @Override
    public ServerResponse appletLogin(WeiXinDto weiXinDto, HttpServletRequest request) throws IOException {

        if (StringUtils.isEmpty(weiXinDto.getCode())) {
            return ServerResponse.createByErrorMessage("code不能为空");
        }

        AppletOrOfficialAccount appletOrOfficialAccount = null;
        log.info("微信小程序APPID：{}", weiXinDto.getAppId());
        if (StringUtils.isEmpty(weiXinDto.getAppId())) {
            appletOrOfficialAccount = appletOrOfficialAccountCommonService.findOneById(7);
        } else {
            appletOrOfficialAccount = appletOrOfficialAccountCommonService.findOneByWeChatAppId(weiXinDto.getAppId());
        }

        if (StringUtils.isEmpty(appletOrOfficialAccount)) {
            return ServerResponse.createByErrorMessage("未找到微信小程序信息，APPID：" + weiXinDto.getAppId());
        }

        ServerResponse sr = this.getAppletUserInfo(weiXinDto, appletOrOfficialAccount);
        if (!sr.getIsSuccess()) {
            return sr;
        }

        Map<String, String> map = (Map<String, String>) sr.getData();
        String s = map.get("jsonObject");
        final String unionId = map.get("unionId");
        final String openid = map.get("openId");
        final String sessionKey = map.get("sessionKey");

        boolean isNewUser = false;
        User user = null;
        if (StringUtils.isEmpty(unionId)) {
            user = userService.getUserByOpenId(openid, UserStatusEnum.WRITE_OFF.getCode());
        } else {
            user = userService.getUserByUnionId(unionId, UserStatusEnum.WRITE_OFF.getCode());
        }
        if (StringUtils.isEmpty(user)) {
            isNewUser = true;
            UserDto userDto = new UserDto();
            userDto.setUnionId(unionId);
            userDto.setOpenId(openid);
            userDto.setAgencyId(1);
            userDto.setNickname("微信用户");
            userDto.setHeadImgUrl(imageProperties.getStaticFileUrl() + "/image/common/member-header-image-default.svg");
            user = userService.registerUser(userDto);
        }

        final String key = String.format(RedisKey.APPLET_WAP_PERPETUAL_SESSION_KEY, user.getId());
        redisCacheTemplate.opsForValue().set(key, sessionKey);

        ServerResponse serverResponse = userService.officialAccountSimulatedAccountLogin(user);
        if (!serverResponse.getIsSuccess()) {
            return serverResponse;
        }

        if (!isNewUser) {
            User updateUser = new User();
            updateUser.setId(user.getId());
            updateUser.setLastLoginTime(new Date());
            updateUser.setLoginCount(user.getLoginCount() + 1);
            userService.updateUser(updateUser);
        }

        UserRole userRole = userRoleService.findOneUserRoleByUserId(user.getId());

        UserVo userInfo = new UserVo();
        userInfo.setId(user.getId());
        if (!StringUtils.isEmpty(user.getName())) {
            userInfo.setName(user.getName());
        } else {
            userInfo.setName(user.getNickname());
        }
        userInfo.setHeadImgUrl(user.getHeadImgUrl());
        userInfo.setToken(user.getToken());
        userInfo.setMobile(user.getUsername());
        userInfo.setRoleId(userRole.getRoleId());
        return ServerResponse.createBySuccess(userInfo);
    }

    private ServerResponse getAppletUserInfo(WeiXinDto weiXinDto, AppletOrOfficialAccount appletOrOfficialAccount) throws IOException {
        long begin = System.currentTimeMillis();
        log.info("--------begin----------" + begin);

        final String jsCode2SessionJson = weChatAppletService.getJsCode2Session(weiXinDto.getCode(), appletOrOfficialAccount.getWeChatAppId(), appletOrOfficialAccount.getWeChatAppSecret());
        if (StringUtils.isEmpty(jsCode2SessionJson)) {
            return ServerResponse.createByErrorMessage("登录不成功");
        }

        final JSONObject jsonObject = JSON.parseObject(jsCode2SessionJson);
        log.info(jsonObject.toJSONString());
        /**
         * {
         *   "unionid": "oCJdU1Y****I1G0t6nA",
         *   "openid": "oROAp45T0******8Jgb_3UGs9Y",
         *   "session_key": "ZWP+*****t4lWIg=="
         * }
         */

        long end = System.currentTimeMillis();
        log.info("--------end----------" + end);
        log.info("--------end----------" + (end - begin));
        String sessionKey = jsonObject.getString("session_key");

        Map<String, String> map = new HashMap<>();
        map.put("jsonObject", JSON.toJSONString(jsonObject));
        map.put("unionId", jsonObject.getString("unionid"));
        map.put("openId", jsonObject.getString("openid"));
        map.put("sessionKey", sessionKey);
        return ServerResponse.createBySuccess(map);
    }

    /**
     * 获取jssdk配置参数
     *
     * @param weiXinDto
     * @return
     */
    @Override
    public ServerResponse getWxJsSdkConfig(WeiXinDto weiXinDto) {

        if (StringUtils.isEmpty(weiXinDto.getUrl())) {
            return ServerResponse.createByErrorMessage("域名路径不能为空");
        }

        return ServerResponse.createBySuccess(weixinService.getWeiXinJsSdkConfig(weiXinDto.getUrl(), weixinService.getJsApiTicket()));
    }

    /**
     * 校验当前微信号是否绑定过
     *
     * @param weiXinDto
     * @return
     * @throws IOException
     */
    @Override
    public ServerResponse bindWeXin(WeiXinDto weiXinDto) throws IOException {

        if (StringUtils.isEmpty(weiXinDto.getCode())) {
            return ServerResponse.createByErrorMessage("code不能为空");
        }

        AppletOrOfficialAccount appletOrOfficialAccount = null;
        log.info("微信小程序APPID：{}", weiXinDto.getAppId());
        if (StringUtils.isEmpty(weiXinDto.getAppId())) {
            appletOrOfficialAccount = appletOrOfficialAccountCommonService.findOneById(7);
        } else {
            appletOrOfficialAccount = appletOrOfficialAccountCommonService.findOneByWeChatAppId(weiXinDto.getAppId());
        }

        if (StringUtils.isEmpty(appletOrOfficialAccount)) {
            return ServerResponse.createByErrorMessage("未找到微信小程序信息，APPID：" + weiXinDto.getAppId());
        }

        ServerResponse sr = this.getAppletUserInfo(weiXinDto, appletOrOfficialAccount);
        if (!sr.getIsSuccess()) {
            return sr;
        }

        Map<String, String> map = (Map<String, String>) sr.getData();
        String s = map.get("jsonObject");
        final String unionId = map.get("unionId");
        final String openid = map.get("openId");
        final String sessionKey = map.get("sessionKey");

        User user = userService.getUserByUnionId(unionId, UserStatusEnum.WRITE_OFF.getCode());
        if (StringUtils.isEmpty(user)) {
            //直接绑定
            User userUpdate = new User();
            userUpdate.setUnionId(unionId);
            userUpdate.setOpenId(openid);
            userUpdate.setId(weiXinDto.getUserInfo().getId());
            userService.updateUser(userUpdate);

            final String key = String.format(RedisKey.APPLET_WAP_PERPETUAL_SESSION_KEY, userUpdate.getId());
            redisCacheTemplate.opsForValue().set(key, sessionKey);
            return ServerResponse.createBySuccess(true);
        } else {
            return ServerResponse.createBySuccess(false);
        }
    }

    /**
     * 只获取 当前微信账号的unionId
     *
     * @param code
     * @return
     */
    @Override
    public Map<String, String> getUnionId(String code) {
        String jsCode2SessionJson = weChatAppletService.getJsCode2Session(code);
        if (StringUtils.isEmpty(jsCode2SessionJson)) {
            throw new RuntimeException("登录不成功");
        }

        final JSONObject jsonObject = JSON.parseObject(jsCode2SessionJson);
        Map<String, String> map = new HashedMap();
        map.put("unionId", jsonObject.getString("unionid"));
        map.put("openId", jsonObject.getString("openid"));
        map.put("sessionKey", jsonObject.getString("session_key"));
        return map;
    }

    @Override
    public ServerResponse getPhoneNumber(WeiXinDto weiXinDto) throws Exception {

        if (StringUtils.isEmpty(weiXinDto.getCode())) {
            return ServerResponse.createByErrorMessage("code不能为空");
        }

        AppletOrOfficialAccount appletOrOfficialAccount = null;
        log.info("微信小程序APPID：{}", weiXinDto.getAppId());
        if (StringUtils.isEmpty(weiXinDto.getAppId())) {
            appletOrOfficialAccount = appletOrOfficialAccountCommonService.findOneById(7);
        } else {
            appletOrOfficialAccount = appletOrOfficialAccountCommonService.findOneByWeChatAppId(weiXinDto.getAppId());
        }

        if (StringUtils.isEmpty(appletOrOfficialAccount)) {
            return ServerResponse.createByErrorMessage("未找到微信小程序信息，APPID：" + weiXinDto.getAppId());
        }

        final String phoneNumber = weChatAppletService.getUserPhoneNumber(weiXinDto.getCode(), appletOrOfficialAccount.getWeChatAppId(), appletOrOfficialAccount.getWeChatAppSecret(), String.format(RedisKey.WEI_XIN_WAP_APPLET_ACCESS_TOKEN, appletOrOfficialAccount.getWeChatAppId()));
        return ServerResponse.createBySuccess(phoneNumber);
    }

}
